package com.lt.flashcard.view;

import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;
import org.zkoss.bind.BindUtils;
import org.zkoss.bind.annotation.BindingParam;
import org.zkoss.bind.annotation.Command;
import org.zkoss.bind.annotation.Init;
import org.zkoss.bind.annotation.NotifyChange;
import org.zkoss.zk.ui.Executions;
import org.zkoss.zk.ui.util.Clients;

import com.lt.flashcard.Utility;
import com.lt.flashcard.model.entity.Flashcard;
import com.lt.flashcard.model.entity.FlashcardSet;
import com.lt.flashcard.model.service.AAService;
import com.lt.flashcard.model.service.FlashcardSetService;
import com.lt.flashcard.model.service.LearningService;
import com.lt.flashcard.model.service.Repository;

public class LearnCtrl {

    private FlashcardSet fcs;
    private Flashcard fc; // Current flashcard
    private List<Flashcard> learnt = new ArrayList<Flashcard>();
    private List<Flashcard> learning = new ArrayList<Flashcard>();
    private int index = -1; // current learning index
    private int hasnext = 0; // has next card or not
    private int hasprevious = 0; // has previous card or not
    private int auto = 0; // auto or not
    private boolean buy = false;
    private String stt = null;

    private static final Logger log = Logger.getLogger(LearnCtrl.class);

    @Init
    public void init() {
        AAService asrv = Repository.getInstance().getAAService();
        String id = Executions.getCurrent().getParameter("id");
        if (StringUtils.isBlank(id) || !asrv.isLogin()) {
            Utility.loginOrAccessDenied(false);
            return;
        }

        FlashcardSetService fcssrv = Repository.getInstance().getFlashcardSetService();
        fcs = fcssrv.findByID(new Long(id));

        if (fcs == null) {
            Utility.loginOrAccessDenied(false);
            return;
        }

        setBuy(fcs.getAdmin() == FlashcardSet.ADMIN_BUY || fcs.getAdmin() == FlashcardSet.ADMIN_YES);

        LearningService lsrv = Repository.getInstance().getLearningService();
        learning = lsrv.buildLearningOrder(fcs);
        setLearnt(lsrv.buildLearntOrder(fcs));

        if (learning.size() > 0) {
            index = 0;
            loadFlashcard();
        }
        setStt(Integer.toString(index + 1) + "/" + Integer.toString(learning.size()));
        hasnext = learning.size() > (index + 1) ? 1 : 0;
        hasprevious = index > 0 ? 1 : 0;

        if (learning.size() == 0)
            Clients.evalJavaScript("showNotice('', 'Bạn đã thuộc tất cả các card')");
    }

    /**
     * Get the flashcard from learning list
     */
    private void loadFlashcard() {
        fc = learning.get(index);
    }

    /**
     * Click on I knew this
     */
    @NotifyChange({ "learnt", "fc" })
    @Command
    public void knewthis() {
        if (fc != null) {
            LearningService srv = Repository.getInstance().getLearningService();
            srv.setFlashcardAsLearnt(fc);
            addToLearnt(fc);
        }
    }

    /**
     * Uncheck on I knew this
     */
    @NotifyChange({ "learnt", "fc" })
    @Command
    public void dontknow() {
        if (fc != null) {
            LearningService srv = Repository.getInstance().getLearningService();
            srv.setFlashcardAsNotLearnt(fc);
            removeFromLearnt(fc);
        }
    }

    @NotifyChange({ "hasnext", "hasprevious", "fc" })
    @Command
    public void next() {
        if (hasnext > 0) {
            index += 1;
            loadFlashcard();
            hasnext = learning.size() > (index + 1) ? 1 : 0;
            hasprevious = 1;
            setStt(Integer.toString(index + 1) + "/" + Integer.toString(learning.size()));
            BindUtils.postNotifyChange(null, null, this, "stt");
            Clients.evalJavaScript("$.showFront();");
        }
    }

    @NotifyChange({ "hasnext", "hasprevious", "fc" })
    @Command
    public void previous() {
        if (hasprevious > 0) {
            index -= 1;
            loadFlashcard();
            hasprevious = index > 0 ? 1 : 0;
            hasnext = 1;
            setStt(Integer.toString(index + 1) + "/" + Integer.toString(learning.size()));
            BindUtils.postNotifyChange(null, null, this, "stt");
            Clients.evalJavaScript("$.showFront();");
        }
    }

    /**
     * Remove from the list of 'tu da thuoc'
     * 
     * @param id
     */
    @NotifyChange("learnt")
    @Command
    public void deleteLearnt(@BindingParam("id") Long id) {
        LearningService lsrv = Repository.getInstance().getLearningService();
        Flashcard cfc = fcs.getFlashcardById(id);
        lsrv.setFlashcardAsUnknow(cfc);
        removeFromLearnt(cfc);
    }

    /**
     * Add a flashcard to learnt list
     * 
     * @param flashcard
     */
    private void addToLearnt(Flashcard flashcard) {
        if (!getLearnt().contains(flashcard))
            getLearnt().add(flashcard);
        setStt(Integer.toString(index + 1) + "/" + Integer.toString(learning.size()));
        BindUtils.postNotifyChange(null, null, this, "stt");
    }

    /**
     * Remove a flashcard from learnt list
     * 
     * @param id
     */
    private void removeFromLearnt(Flashcard card) {
        getLearnt().remove(card);
        // update learning list
        if (!learning.contains(card)) {
            learning.add(card);

            if (index == -1)
                index = 0;
            hasnext = learning.size() > (index + 1) ? 1 : 0;
            setStt(Integer.toString(index + 1) + "/" + Integer.toString(learning.size()));
            BindUtils.postNotifyChange(null, null, this, "hasnext");
            BindUtils.postNotifyChange(null, null, this, "stt");
            if (fc == null)
                loadFlashcard();
        }
        // update the display of current learning card
        if (fc != null && fc.getId().equals(card.getId()))
            BindUtils.postNotifyChange(null, null, this, "fc");
    }

    public Flashcard getFc() {
        Clients.evalJavaScript("$.doScaleContent()");
        return fc;
    }

    public void setFc(Flashcard fc) {
        this.fc = fc;
    }

    public int getIndex() {
        return index;
    }

    public void setIndex(int index) {
        this.index = index;
    }

    public int getHasnext() {
        return hasnext;
    }

    public void setHasnext(int hasnext) {
        this.hasnext = hasnext;
    }

    public int getHasprevious() {
        return hasprevious;
    }

    public void setHasprevious(int hasprevious) {
        this.hasprevious = hasprevious;
    }

    public int getAuto() {
        return auto;
    }

    public void setAuto(int auto) {
        this.auto = auto;
    }

    /**
     * @return the fcs
     */
    public FlashcardSet getFcs() {
        return fcs;
    }

    /**
     * @param fcs
     *            the fcs to set
     */
    public void setFcs(FlashcardSet fcs) {
        this.fcs = fcs;
    }

    /**
     * @return the learning
     */
    public List<Flashcard> getLearning() {
        return learning;
    }

    /**
     * @param learning
     *            the learning to set
     */
    public void setLearning(List<Flashcard> learning) {
        this.learning = learning;
    }

    /**
     * @return the learnt
     */
    public List<Flashcard> getLearnt() {
        Clients.evalJavaScript("$.setBackground()");
        return learnt;
    }

    /**
     * @param learnt
     *            the learnt to set
     */
    public void setLearnt(List<Flashcard> learnt) {
        this.learnt = learnt;
    }

    public boolean isBuy() {
        return buy;
    }

    public void setBuy(boolean buy) {
        this.buy = buy;
    }

    public String getStt() {
        return stt;
    }

    public void setStt(String stt) {
        this.stt = stt;
    }

}